home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / p_misc / 7p203upp.exe / V203SRC.LZH / UTILS.C < prev   
C/C++ Source or Header  |  1992-07-17  |  30KB  |  1,422 lines

  1. #include "7plus.h"
  2. #include "globals.h"
  3.  
  4. #ifdef __unix__
  5.  #ifdef __M_XENIX__
  6.   struct utimbuf {
  7.    time_t actime;
  8.    time_t modtime;
  9.   };
  10.   extern time_t mktime (struct tm *utm);
  11.  #else
  12.   #include <utime.h>
  13.  #endif
  14. #endif
  15.  
  16. static char no[] = NO, yes[] = YES, always[] = ALWAYS;
  17.  
  18. /*
  19. *** get a line from file. don't care about type of line separator.
  20. ***
  21. ***
  22.  */
  23.  
  24. char *my_fgets (char *string, register n, FILE *rein)
  25. {
  26.   register in, i;
  27.  
  28.   if (feof (rein))
  29.     return (NULL);
  30.  
  31.   i = 0;
  32.   while ((in = fgetc (rein)) != EOF)
  33.   {
  34.     if (in == 0x0d)
  35.     {
  36.       if ((in = fgetc (rein)) != 0x0a)
  37.         if (in != EOF)
  38.           ungetc (in, rein);
  39.       in = 0x0a;
  40.     }
  41.     string[i++] = (char) in;
  42.     if (i == n || in == 0x0a)
  43.       break;
  44.   }
  45.   string[i] = EOS;
  46.   return (string);
  47.  
  48. /*
  49. ***
  50. *** Write a byte to file.
  51. ***
  52.  */
  53.  
  54. int my_putc (int outchar, FILE *out)
  55. {
  56.   register x;
  57.  
  58.   if ((x = putc ((char) outchar, out)) == EOF)
  59.   {
  60.     printf ("\007\nWrite error! Can't continue.\n");
  61.     exit (1);
  62.   }
  63.   return (x);
  64. }
  65.  
  66. /*
  67. *** Get crc and line number from code line.
  68. ***
  69. ***
  70.  */
  71.  
  72. void crc_n_lnum (uint *crc, int *linenumber, char *line)
  73. {
  74.   register ulong cs;
  75.  
  76.   cs = 0xb640L * decode[(byte)line[66]] +
  77.        0xd8L   * decode[(byte)line[65]] +
  78.                  decode[(byte)line[64]];
  79.  
  80.   *linenumber = (int) (cs >> 14);   /* upper 9 bits are the line number */
  81.   *crc = (uint) (cs & 0x3fffL);     /* lower 14 bits are the CRC */
  82. }
  83.  
  84. /*
  85. *** Get crc2 from code line.
  86. ***
  87. ***
  88.  */
  89.  
  90. void crc2 (uint *crc, char *line)
  91. {
  92.  
  93.   *crc = 0xd8 * decode[(byte)line[68]] +
  94.                 decode[(byte)line[67]];
  95. }
  96.  
  97. /*
  98. *** Whip up 2nd CRC
  99. ***
  100. ***
  101.  */
  102.  
  103. void add_crc2 (char *line)
  104. {
  105.   register uint crc;
  106.   register int i;
  107.  
  108.   /* Whip up 2nd CRC */
  109.   crc = 0;
  110.   for (i=66;i>-1;i--)
  111.     crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte) line[i]);
  112.   crc &= 0x7fff;
  113.  
  114.   i = 67;
  115.   line[i++] = code[crc % 0xd8];
  116.   line[i++] = code[crc / 0xd8];
  117.   line[i] = EOS;
  118. }
  119.  
  120. /*
  121. *** mini-crc for header. safe enough...
  122. ***
  123. ***
  124.  */
  125.  
  126. int mcrc (char *line, int flag)
  127. {
  128.   register int i, j;
  129.   register uint crc;
  130.   char test[3], *p;
  131.  
  132.   sprintf (test, "\xb0\xb1");
  133.  
  134.   if ((p = strstr (line, test)) == NULL)
  135.     return (0);
  136.  
  137.   j = (int) (p - line) + 4;
  138.  
  139.   for (i=crc=0; i<j; i++)
  140.     crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte)line[i]);
  141.   crc %= 216;
  142.   if (!flag)
  143.   {
  144.     if (crc == (uint) decode[(byte)line[j]])
  145.       return (1);
  146.     else
  147.       return (0);
  148.   }
  149.   else
  150.     line[j] = code[(byte)crc];
  151.  
  152.   return (crc);
  153. }
  154.  
  155. /*
  156. *** read info from indexfile
  157. ***
  158. ***
  159.  */
  160.  
  161. int read_index (FILE *ifile, struct m_index *index)
  162. {
  163.   int j;
  164.   ulong i, begin, end;
  165.  
  166.   #ifdef _CHSIZE_OK
  167.    fseek (ifile, -4L, SEEK_END);
  168.    fseek (ifile, read_ulong (ifile), SEEK_SET);
  169.   #endif
  170.  
  171.   /* clear index */
  172.   for (j = 0;j < 4080; j++)
  173.     index->lines_ok[j] = 0UL;
  174.  
  175.   my_fgets (index->full_name, 12, ifile);
  176.   if (strcmp(index->full_name, "7PLUS-index\x0a"))
  177.   {
  178.     printf ("\007No index info found.\n");
  179.     return (1);
  180.   }
  181.   my_fgets (index->filename, 13, ifile);
  182.   index->filename[(int)strlen(index->filename)-1] = EOS;
  183.   my_fgets (index->full_name, 257, ifile);
  184.   index->full_name[(int)strlen(index->full_name)-1] = EOS;
  185.   index->timestamp = read_ulong (ifile);
  186.   index->splitsize = read_uint  (ifile);
  187.   index->lines_left= (long) read_ulong (ifile);
  188.  
  189.   /* convert defect list into bitvektor */
  190.   while (1==1)
  191.   {
  192.     if ((begin = read_ulong (ifile)) == 0xffffffffUL)
  193.       break;
  194.     end = read_ulong (ifile);
  195.  
  196.     if ((end>>5) > (begin>>5))
  197.       for (i = begin;i < ((begin |31UL) + 1UL); i++)
  198.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  199.     else
  200.     {
  201.       for (i = begin;i < end; i++)
  202.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  203.       continue;
  204.     }
  205.  
  206.     for (i = (begin>>5) +1; i < (end>>5); i++)
  207.       index->lines_ok[(int)i] = 0xffffffffUL;
  208.  
  209.     if (end&31)
  210.       for (i = end &0xffffffe0UL; i < end; i++)
  211.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  212.   }
  213.   index->length = read_ulong (ifile);
  214.  
  215.   #ifdef _CHSIZE_OK
  216.    fseek (ifile, 0UL, SEEK_SET);
  217.   #endif
  218.  
  219.   return (0);
  220. }
  221.  
  222. /*
  223. *** write info to indexfile
  224. ***
  225. ***
  226.  */
  227.  
  228. int write_index (FILE *ifile, struct m_index *index, int flag)
  229. {
  230.   int j, part, prevpart, lines;
  231.   ulong i, begin, end;
  232.  
  233.   part = prevpart = lines = 0;
  234.   begin = end = 0UL;
  235.  
  236.   if (!flag)
  237.   {
  238.     #ifdef _CHSIZE_OK
  239.      fseek (ifile, index->length, SEEK_SET);
  240.     #endif
  241.  
  242.     fprintf (ifile, "7PLUS-index\n");
  243.     fprintf (ifile, "%s\n", index->filename);
  244.     fprintf (ifile, "%s\n", index->full_name);
  245.     write_ulong (ifile, index->timestamp);
  246.     write_uint  (ifile, index->splitsize);
  247.     write_ulong (ifile, (ulong) index->lines_left);
  248.   }
  249.   /* convert bitvektor into defect list */
  250.   i = 0UL;
  251.   j = 0;
  252.   while (1==1)
  253.   {
  254.     while (j < 4080 && !(index->lines_ok[j] &(1UL <<(i & 31UL))))
  255.     {
  256.       if (!(i&31UL) && index->lines_ok[j] == 0UL)
  257.       {
  258.         j++;
  259.         i = (ulong) j<<5;
  260.       }
  261.       else
  262.       {
  263.         i++;
  264.         j = (int) i>>5;
  265.       }
  266.     }
  267.  
  268.     if (j == 4080)
  269.       break;
  270.  
  271.     begin = i;
  272.  
  273.     do
  274.     {
  275.       if (!(i&31UL) && index->lines_ok[j] == 0xffffffffUL)
  276.       {
  277.         j++;
  278.         i = (ulong) j<<5;
  279.       }
  280.       else
  281.       {
  282.         i++;
  283.         j = (int) i>>5;
  284.       }
  285.     }
  286.     while (j < 4080 && (index->lines_ok[j] &(1UL <<(i & 31UL))));
  287.  
  288.     end = i;
  289.  
  290.     if (!flag)
  291.     {
  292.       write_ulong (ifile, begin);
  293.       write_ulong (ifile, end);
  294.     }
  295.     else
  296.     {
  297.       for (i = begin; i < end; i++)
  298.       {
  299.         part = (int) i / index->splitsize +1;
  300.         if (part != prevpart)
  301.         {
  302.           if (prevpart)
  303.           {
  304.             if (!(lines % 18) && lines)
  305.               fprintf (ifile, delimit);
  306.             lines = 0;
  307.             fprintf (ifile, "FFF%s", delimit);
  308.           }
  309.           prevpart = part;
  310.           fprintf (ifile, "%02X%s", part, delimit);
  311.         }
  312.  
  313.         lines++; /* Number of missing or corrupted lines in this part. */
  314.         fprintf (ifile, "%03X", (uint)(i % index->splitsize));
  315.         if (!(lines % 18) && lines)
  316.         {
  317.           fprintf (ifile, delimit);
  318.           lines = 0;
  319.         }
  320.         else
  321.           fprintf (ifile, " ");
  322.       }
  323.     }
  324.   }
  325.  
  326.   if (!flag)
  327.   {
  328.     write_ulong (ifile, 0xffffffffUL);
  329.     write_ulong (ifile, index->length);
  330.     #ifdef _CHSIZE_OK
  331.      chsize (fileno (ifile), ftell (ifile));
  332.     #endif
  333.   }
  334.   else
  335.   {
  336.     if (!(lines % 18) && lines)
  337.       fprintf (ifile, delimit);
  338.     fprintf (ifile, "FFF%s", delimit);
  339.   }
  340.   return (0);
  341. }
  342.  
  343. /*
  344. *** Reading/writing unsigned long(32bit)/int(16)
  345. ***
  346. ***
  347.  */
  348.  
  349. ulong read_ulong (FILE *in)
  350. {
  351.   return ((ulong)fgetc (in)       +
  352.          ((ulong)fgetc (in) <<8 ) +
  353.          ((ulong)fgetc (in) <<16) +
  354.          ((ulong)fgetc (in) <<24));
  355. }
  356.  
  357. uint read_uint (FILE *in)
  358. {
  359.   return ((uint)fgetc (in)       +
  360.          ((uint)fgetc (in) <<8 ));
  361. }
  362.  
  363. void write_ulong (FILE *out, ulong val)
  364. {
  365.   my_putc ((int) (val     &0xffUL), out);
  366.   my_putc ((int)((val>>8 )&0xffUL), out);
  367.   my_putc ((int)((val>>16)&0xffUL), out);
  368.   my_putc ((int)((val>>24)&0xffUL), out);
  369. }
  370.  
  371. void write_uint (FILE *out, uint val)
  372. {
  373.   my_putc ((int) (val    &0xffU), out);
  374.   my_putc ((int)((val>>8)&0xffU), out);
  375. }
  376.  
  377. /*
  378. *** read a file, search for s1, calculate CRC until s2 is found.
  379. *** flag == 1: compare calculated an read CRC.
  380. *** flag == 0: insert CRC into file.
  381.  */
  382.  
  383. int crc_file (char *file, char *s1, char *s2, int flag)
  384. {
  385.   char line[81], *p;
  386.   uint crc, cs;
  387.   int i, j, k;
  388.   FILE *in;
  389.  
  390.   crc = cs = 0;
  391.   p = NULLCP;
  392.  
  393.   if (!(in = fopen (file, OPEN_RANDOM_BINARY)))
  394.   {
  395.     printf (cant, file);
  396.     return (2);
  397.   }
  398.  
  399.   i = (int) strlen (s1);
  400.   k = (int) strlen (s2);
  401.  
  402.   j = 1;
  403.  
  404.   do
  405.   {
  406.     if (my_fgets (line, 80, in) == NULL)
  407.       break;
  408.  
  409.     j = strncmp (line, s1, i);
  410.   }
  411.   while (j);
  412.  
  413.   if (j)
  414.     p = s1;
  415.   else
  416.   {
  417.     p = s2;
  418.     do
  419.     {
  420.       for (i=0;i!=(int)strlen(line);i++)
  421.         crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte)line[i]);
  422.  
  423.       j = strncmp (line, s2, k);
  424.  
  425.       if (!j)
  426.         continue;
  427.  
  428.       if (my_fgets (line, 80, in) == NULL)
  429.         break;
  430.     }
  431.     while (j);
  432.   }
  433.  
  434.   if (j)
  435.   {
  436.     printf ("\n\007Can't calculate CRC\n");
  437.     printf ("String '%s' not found in '%s'.\nBreak.\n", p, file);
  438.     return (7);
  439.   }
  440.  
  441.   /* evaluate CRC */
  442.   if (flag)
  443.   {
  444.     my_fgets (line, 80, in);
  445.     fclose (in);
  446.     if (!line || strncmp ("CRC ", line, 4))
  447.     {
  448.       printf ("\n'%s': no CRC found.\n(File may be corrupted or from version \
  449. earlier than 7PLUS v1.5)\n", file);
  450.       return (17);
  451.     }
  452.     cs = get_hex (line+4);
  453.     if (cs == crc)
  454.       return (0);
  455.  
  456.     printf ("\007\n'%s' is corrupted. Break.\n", file);
  457.     return (7);
  458.   }
  459.  
  460.   /* insert CRC into file */
  461.   fseek (in, 0UL, SEEK_CUR);
  462.   fprintf (in, "CRC %04X", crc);
  463.   fclose (in);
  464.  
  465.   return (0);
  466. }
  467.  
  468. /*
  469. *** Copy a file.
  470. ***
  471. ***
  472.  */
  473.  
  474. int copy_file (char *to, char *from, ulong timestamp)
  475. {
  476.   FILE *_from, *_to;
  477.   int _char, stat;
  478.  
  479.   stat = 0;
  480.  
  481.   _from = fopen (from, OPEN_READ_BINARY);
  482.   _to   = fopen (to,   OPEN_WRITE_BINARY);
  483.  
  484.   while ((_char = getc (_from)) != EOF)
  485.     if ((stat = putc (_char, _to)) == EOF)
  486.       break;
  487.  
  488.   fclose (_from);
  489.  
  490.  #if defined (__MSDOS__) || (__TOS__)
  491.   if (timestamp)
  492.     set_filetime (_to, timestamp);
  493.  
  494.   fclose (_to);
  495.  #else
  496.   fclose (_to);
  497.  
  498.   if (timestamp)
  499.     set_filetime (to, timestamp);
  500.  #endif
  501.  
  502.   if (stat == EOF)
  503.   {
  504.     printf ("\007\nFatal error. Can't write '%s'! Break.\n", to);
  505.     exit (1);
  506.   }
  507.   return (0);
  508. }
  509.  
  510. /*
  511. *** Replace one file with another
  512. ***
  513. ***
  514.  */
  515.  
  516. void replace (char *old, char *new, ulong timestamp)
  517. {
  518.   unlink (old);
  519.  
  520.   if (rename (new, old))
  521.   {
  522.     copy_file (old, new, timestamp);
  523.     unlink (new);
  524.   }
  525.   else
  526.   {
  527.     if (timestamp)
  528.     {
  529.      #if defined (__MSDOS__) || (__TOS__)
  530.       FILE *_file;
  531.  
  532.       _file = fopen (old, OPEN_APPEND_BINARY);
  533.       set_filetime (_file, timestamp);
  534.       fclose (_file);
  535.      #else
  536.       set_filetime (old, timestamp);
  537.      #endif
  538.     }
  539.   }
  540. }
  541.  
  542. /*
  543. *** Kill all files that aren't needed any more
  544. ***
  545. ***
  546.  */
  547.  
  548. void kill_em (char *name, char *inpath, char *one, char *two,
  549.               char *three, char *four, char *five)
  550. {
  551.   char *p, newname[MAXPATH];
  552.   int i, j, k, len;
  553.  
  554.   k = 0;
  555.  
  556.   for (i = 0; i < 5; i++)
  557.   {
  558.     if (!i)
  559.       printf ("\n");
  560.  
  561.     switch (i)
  562.     {
  563.       case 0:  p = one;
  564.                break;
  565.       case 1:  p = two;
  566.                break;
  567.       case 2:  p = three;
  568.                break;
  569.       case 3:  p = four;
  570.                break;
  571.       case 4:  p = five;
  572.  
  573.       default: p = NULLCP;
  574.     }
  575.     if (!p)
  576.      break;
  577.  
  578.     len = strlen(p);
  579.  
  580.     for (j = 1; j <256; j++)
  581.     {
  582.       if (len == 3)
  583.         sprintf (newname, "%s%s.%s", inpath, name, p);
  584.       else
  585.         sprintf (newname, "%s%s.%s%02x", inpath, name, p, j);
  586.  
  587.       if (unlink (newname))
  588.         break;
  589.  
  590.       k++;
  591.  
  592.       printf ("Deleting: %s\r", newname);
  593.       fflush (stdout);
  594.  
  595.       if (len == 3)
  596.         break;
  597.     }
  598.   }
  599.   if (k)
  600.     printf ("\n");
  601. }
  602.  
  603. /*
  604. ***
  605. ***
  606. ***
  607.  */
  608.  
  609. void kill_dest (FILE *in, FILE *out, char *name)
  610. {
  611.     if (out)
  612.       fclose (out);
  613.     if (in)
  614.       fclose (in);
  615.     if (*name)
  616.       unlink (name);
  617. }
  618.  
  619. /*
  620. ***
  621. ***  test if a file exists at all
  622. ***
  623.  */
  624.  
  625. int test_exist (char *filename)
  626. {
  627.   FILE *in = NULLFP;
  628.  
  629.   if ((in = fopen (filename, OPEN_READ_TEXT)) != NULLFP)
  630.   {
  631.     fclose (in);
  632.     return (0);
  633.   }
  634.   return (1);
  635. }
  636.  
  637.  
  638. /*
  639. ***  test if outputfile already exists. prompt for overwrite or
  640. ***  new name.
  641. ***
  642.  */
  643.  
  644. int test_file (FILE *in, char *destnam, int flag, int namsize)
  645. {
  646.    FILE *out;
  647.    int  i, ret;
  648.  
  649.    ret = 0;
  650.  
  651.    if (noquery)
  652.      return (ret);
  653.  
  654.    /* Loop as long as file can be opened. */
  655.    while ((out = fopen (destnam, OPEN_READ_BINARY)) != NULLFP)
  656.    {
  657.      ret = 1;
  658.      printf ("\007\nOutputfile '%s' already exists, overwrite? [y/n/a] ", destnam);
  659.      do
  660.      {
  661.        i = toupper (getch());
  662.  
  663.        if (i == 'N')
  664.        {
  665.          if (flag)
  666.          {
  667.            printf ("%s\n\nEnter new name (max %d chars)\n", no, namsize);
  668.            printf ("or simply press ENTER to break : ");
  669.            if (namsize == 12)
  670.              strlwr (destnam);
  671.            i = getc(stdin);
  672.            if(i != '\n')
  673.            {
  674.              ungetc(i, stdin);
  675.              scanf ("%s", destnam);
  676.            }
  677.            else
  678.              destnam[0] = EOS;
  679.            destnam[namsize] = EOS;
  680.          }
  681.          else
  682.            *destnam = EOS;
  683.          if (!strlen (destnam))
  684.          {
  685.            if (!flag)
  686.              printf ("%s\n", no);
  687.            printf ("Break.\n");
  688.            if (in)
  689.              fclose (in);
  690.            exit (10);
  691.          }
  692.          i = 0xff; /* indicate, that new name has been specified */
  693.        }
  694.      }
  695.      while (i != 'Y' && i != 'A' && i != 0xff);
  696.  
  697.      if (i != 0xff)
  698.      {
  699.        if (i == 'A')
  700.        {
  701.          printf ("%s\n", always);
  702.          noquery = 1;
  703.        }
  704.        else
  705.          printf ("%s\n", yes);
  706.      }
  707.      printf ("\n");
  708.  
  709.      fclose (out);
  710.  
  711.      if (i != 0xff)
  712.        break;
  713.    }
  714.  
  715.    return (ret);
  716. }
  717.  
  718.  
  719. /*
  720. *** initialize decoding table
  721. ***
  722. ***
  723.  */
  724.  
  725. void init_decodetab (void)
  726. {
  727.   register i;
  728.   register byte j;
  729.  
  730.   for (i = 0; i < 256; i++)
  731.     decode[i] = 255;
  732.  
  733.   j = 0;
  734.   for (i = 0x21; i < 0x2a; i++)
  735.     decode[i] = j++;
  736.  
  737.   for (i = 0x2b; i < 0x7f; i++)
  738.     decode[i] = j++;
  739.  
  740.   for (i = 0x80; i < 0x91; i++)
  741.     decode[i] = j++;
  742.  
  743.   decode[0x92] = j++;
  744.  
  745.   for (i = 0x94; i < 0xfd; i++)
  746.     decode[i] = j++;
  747. }
  748.  
  749. /*
  750. *** initialize encoding table
  751. ***
  752. ***
  753.  */
  754.  
  755. void init_codetab (void)
  756. {
  757.   register byte i, j;
  758.  
  759.   j = 0;
  760.  
  761.   for (i = 0x21; i < 0x2a; i++, j++)
  762.     code[j] = i;
  763.  
  764.   for (i = 0x2b; i < 0x7f; i++, j++)
  765.     code[j] = i;
  766.  
  767.   for (i = 0x80; i < 0x91; i++, j++)
  768.     code[j] = i;
  769.  
  770.   code[j++] = 146;
  771.  
  772.   for (i = 0x94; i < 0xfd; i++, j++)
  773.     code[j] = i;
  774. }
  775.  
  776. /*
  777. *** Tnx to DC4OX.
  778. ***
  779. *** calculate CRC-table
  780. ***
  781.  */
  782.  
  783. void init_crctab (void)
  784. {
  785.   uint m, n, r, mask;
  786.  
  787.   static uint bitrmdrs[] = { 0x9188,0x48C4,0x2462,0x1231,
  788.                              0x8108,0x4084,0x2042,0x1021 };
  789.  
  790.   for (n = 0; n < 256; ++n)
  791.   {
  792.     for (mask = 0x0080, r = 0, m = 0; m < 8; ++m, mask >>= 1)
  793.       if (n & mask)
  794.         r = bitrmdrs[m] ^ r;
  795.     crctab[n] = r;
  796.   }
  797. }
  798.  
  799. /*
  800. *** Create a MSDOS/ATARI compatible filename.
  801. ***
  802. ***
  803.  */
  804.  
  805. void build_DOS_name (char *name)
  806. {
  807.   char tmp[MAXFNAME];
  808.   register i, j;
  809.  
  810.   i = j = 0;
  811.  
  812.   strcpy (tmp, name);
  813.   strlwr (tmp);
  814.  
  815.   if (*tmp)
  816.   {
  817.     do
  818.     {
  819.       tmp[i] &= 127;
  820.       if (strchr (" <>=,;:*?&[]()/.\\\"~+@", tmp[i]) == NULL)
  821.         name[j++] = tmp[i];
  822.     }
  823.     while (tmp[++i]);
  824.  
  825.     name[j] = EOS;
  826.   }
  827. }
  828.  
  829. #if defined (__MSDOS__) || (__TOS__)
  830.  /*
  831.  *** Get file's timestamp and package it into a 32-bit word (MS_DOS-format)
  832.  ***
  833.  ***
  834.   */
  835.  ulong get_filetime (FILE *_file)
  836.  {
  837.   ulong    ftimestamp;
  838.  
  839.   if (getftime (fileno(_file), (struct ftime *)&ftimestamp) == EOF)
  840.     printf ("\007\nCan't get file's timestamp!\n");
  841.  
  842.  #ifdef __TOS__
  843.   ftimestamp = swapl(ftimestamp);
  844.  #endif
  845.  
  846.   return (ftimestamp);
  847.  }
  848.  
  849.  /*
  850.  *** Set file's timestamp
  851.  ***
  852.  ***
  853.   */
  854.  void set_filetime (FILE *_file, ulong ftimestamp)
  855.  {
  856.  #ifdef __TOS__
  857.   ftimestamp = swapl(ftimestamp);
  858.  #endif
  859.  
  860.   if (setftime (fileno(_file), (struct ftime *)&ftimestamp) == EOF)
  861.     printf ("\007\nCan't set file's timestamp!");
  862.  }
  863. #else
  864.  #ifndef _HAVE_GMTIME
  865.   /*
  866.   * mktime function from GNU C library V1.03; modified:
  867.   * - expanded DEFUN and CONST macros from ansidecl.h
  868.   * - inserted __isleap macro from time.h
  869.   * - inserted __mon_lengths array and __offtime function from offtime.c
  870.   * - inserted gmtime function from gmtime.c
  871.   * - commented out call of localtime function
  872.   * Be aware of the following copyright message for mktime !!!
  873.   */
  874.  
  875.   /* Copyright (C) 1991 Free Software Foundation, Inc.
  876.   This file is part of the GNU C Library.
  877.  
  878.   The GNU C Library is free software; you can redistribute it and/or
  879.   modify it under the terms of the GNU Library General Public License as
  880.   published by the Free Software Foundation; either version 2 of the
  881.   License, or (at your option) any later version.
  882.  
  883.   The GNU C Library is distributed in the hope that it will be useful,
  884.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  885.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  886.   Library General Public License for more details.
  887.  
  888.   You should have received a copy of the GNU Library General Public
  889.   License along with the GNU C Library; see the file COPYING.LIB.  If
  890.   not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  891.   Cambridge, MA 02139, USA.  */
  892.  
  893.  
  894.   /* How many days are in each month.  */
  895.   const unsigned short int __mon_lengths[2][12] =
  896.     {
  897.       /* Normal years.  */
  898.       { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  899.       /* Leap years.  */
  900.       { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  901.     };
  902.  
  903.   #define  __isleap(year)  \
  904.     ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  905.  
  906.   #define  invalid()  return (time_t) -1
  907.  
  908.  
  909.   #define  SECS_PER_HOUR  (60 * 60)
  910.   #define  SECS_PER_DAY  (SECS_PER_HOUR * 24)
  911.  
  912.   /* Returns the `struct tm' representation of *T,
  913.      offset OFFSET seconds east of UCT.  */
  914.   struct tm *
  915.   __offtime (const time_t *t, long int offset)
  916.   {
  917.     static struct tm tbuf;
  918.     register long int days, rem;
  919.     register int y;
  920.     register const unsigned short int *ip;
  921.  
  922.     if (t == NULL)
  923.       return NULL;
  924.  
  925.     days = *t / SECS_PER_DAY;
  926.     rem = *t % SECS_PER_DAY;
  927.     rem += offset;
  928.     while (rem < 0)
  929.     {
  930.       rem += SECS_PER_DAY;
  931.       --days;
  932.     }
  933.     while (rem >= SECS_PER_DAY)
  934.     {
  935.       rem -= SECS_PER_DAY;
  936.       ++days;
  937.     }
  938.     tbuf.tm_hour = rem / SECS_PER_HOUR;
  939.     rem %= SECS_PER_HOUR;
  940.     tbuf.tm_min = rem / 60;
  941.     tbuf.tm_sec = rem % 60;
  942.     /* January 1, 1970 was a Thursday.  */
  943.     tbuf.tm_wday = (4 + days) % 7;
  944.     if (tbuf.tm_wday < 0)
  945.       tbuf.tm_wday += 7;
  946.     y = 1970;
  947.     while (days >= (rem = __isleap(y) ? 366 : 365))
  948.     {
  949.       ++y;
  950.       days -= rem;
  951.     }
  952.     while (days < 0)
  953.     {
  954.       --y;
  955.       days += __isleap(y) ? 366 : 365;
  956.     }
  957.     tbuf.tm_year = y - 1900;
  958.     tbuf.tm_yday = days;
  959.     ip = __mon_lengths[__isleap(y)];
  960.     for (y = 0; days >= ip[y]; ++y)
  961.       days -= ip[y];
  962.     tbuf.tm_mon = y;
  963.     tbuf.tm_mday = days + 1;
  964.     tbuf.tm_isdst = -1;
  965.  
  966.     return &tbuf;
  967.   }
  968.  
  969.  
  970.   /* Return the `struct tm' representation of *T in UTC.  */
  971.   struct tm *
  972.   gmtime (const time_t *t)
  973.   {
  974.     return __offtime(t, 0L);
  975.   }
  976.  #endif /* ifndef _HAVE_GMTIME */
  977.  
  978.  #ifndef _HAVE_MKTIME
  979.  
  980.   /* Return the `time_t' representation of TP and normalizes TP.
  981.      Return (time_t) -1 if TP is not representable as a `time_t'.
  982.      Note that 31 Dec 1969 23:59:59 is not representable
  983.      because it is represented as (time_t) -1.  */
  984.   time_t mktime (register struct tm *tp)
  985.   {
  986.     static struct tm min, max;
  987.     static char init = 0;
  988.  
  989.     register time_t result;
  990.     register time_t t;
  991.     register int i;
  992.     register const unsigned short *l;
  993.     register struct tm *new;
  994.     time_t end;
  995.  
  996.     if (tp == NULL)
  997.     {
  998.       errno = EINVAL;
  999.       invalid();
  1000.     }
  1001.  
  1002.     if (!init)
  1003.     {
  1004.       init = 1;
  1005.       end = (time_t) LONG_MIN;
  1006.       new = gmtime(&end);
  1007.       if (new != NULL)
  1008.         min = *new;
  1009.       else
  1010.         min.tm_sec = min.tm_min = min.tm_hour =
  1011.       min.tm_mday = min.tm_mon = min.tm_year = INT_MIN;
  1012.  
  1013.       end = (time_t) LONG_MAX;
  1014.       new = gmtime(&end);
  1015.       if (new != NULL)
  1016.         max = *new;
  1017.       else
  1018.         max.tm_sec = max.tm_min = max.tm_hour =
  1019.       max.tm_mday = max.tm_mon = max.tm_year = INT_MAX;
  1020.     }
  1021.  
  1022.     /* Make all the elements of TP that we pay attention to
  1023.        be within the ranges of reasonable values for those things.  */
  1024.     #define  normalize(elt, min, max, nextelt)\
  1025.     while (tp->elt < min)                     \
  1026.     {                                         \
  1027.       --tp->nextelt;                          \
  1028.       tp->elt += max + 1;                     \
  1029.     }                                         \
  1030.     while (tp->elt > max)                     \
  1031.     {                                         \
  1032.       ++tp->nextelt;                          \
  1033.       tp->elt -= max + 1;                     \
  1034.     }
  1035.  
  1036.     normalize (tm_sec, 0, 59, tm_min);
  1037.     normalize (tm_min, 0, 59, tm_hour);
  1038.     normalize (tm_hour, 0, 24, tm_mday);
  1039.  
  1040.     /* Normalize the month first so we can use
  1041.        it to figure the range for the day.  */
  1042.     normalize (tm_mon, 0, 11, tm_year);
  1043.     normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
  1044.       tm_mon);
  1045.  
  1046.     /* Normalize the month again, since normalizing
  1047.        the day may have pushed it out of range.  */
  1048.     normalize (tm_mon, 0, 11, tm_year);
  1049.  
  1050.     /* Normalize the day again, because normalizing
  1051.        the month may have changed the range.  */
  1052.     normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
  1053.       tm_mon);
  1054.  
  1055.    /* Check for out-of-range values.  */
  1056.    #define  lowhigh(field, minmax, cmp)  (tp->field cmp minmax.field)
  1057.    #define  low(field)                   lowhigh(field, min, <)
  1058.    #define  high(field)                  lowhigh(field, max, >)
  1059.    #define  oor(field)                   (low(field) || high(field))
  1060.    #define  lowbound(field)              (tp->field == min.field)
  1061.    #define  highbound(field)             (tp->field == max.field)
  1062.    if (oor(tm_year))
  1063.      invalid();
  1064.    else
  1065.      if (lowbound(tm_year))
  1066.      {
  1067.        if (low(tm_mon))
  1068.          invalid();
  1069.        else
  1070.          if (lowbound(tm_mon))
  1071.          {
  1072.            if (low(tm_mday))
  1073.              invalid();
  1074.            else
  1075.              if (lowbound(tm_mday))
  1076.              {
  1077.                if (low(tm_hour))
  1078.                  invalid();
  1079.                else
  1080.                  if (lowbound(tm_hour))
  1081.                  {
  1082.                    if (low(tm_min))
  1083.                      invalid();
  1084.                    else
  1085.                      if (lowbound(tm_min))
  1086.                      {
  1087.                        if (low(tm_sec))
  1088.                        invalid();
  1089.                      }
  1090.                  }
  1091.              }
  1092.          }
  1093.      }
  1094.      else
  1095.        if (highbound(tm_year))
  1096.        {
  1097.          if (high(tm_mon))
  1098.            invalid();
  1099.          else
  1100.            if (highbound(tm_mon))
  1101.            {
  1102.              if (high(tm_mday))
  1103.                invalid();
  1104.              else
  1105.                if (highbound(tm_mday))
  1106.                {
  1107.                  if (high(tm_hour))
  1108.                    invalid();
  1109.                  else
  1110.                    if (highbound(tm_hour))
  1111.                    {
  1112.                      if (high(tm_min))
  1113.                        invalid();
  1114.                      else
  1115.                        if (highbound(tm_min))
  1116.                        {
  1117.                          if (high(tm_sec))
  1118.                          invalid();
  1119.                        }
  1120.                    }
  1121.                }
  1122.            }
  1123.        }
  1124.     t = 0;
  1125.     for (i = 1970; i > 1900 + tp->tm_year; --i)
  1126.       t -= __isleap(i) ? 366 : 365;
  1127.     for (i = 1970; i < 1900 + tp->tm_year; ++i)
  1128.       t += __isleap(i) ? 366 : 365;
  1129.     l = __mon_lengths[__isleap(1900 + tp->tm_year)];
  1130.     for (i = 0; i < tp->tm_mon; ++i)
  1131.       t += l[i];
  1132.     t += tp->tm_mday - 1;
  1133.     result = ((t * 60 * 60 * 24) +
  1134.              (tp->tm_hour * 60 * 60) +
  1135.              (tp->tm_min * 60) +
  1136.               tp->tm_sec);
  1137.  
  1138.     end = result;
  1139.    #if 0
  1140.     if (tp->tm_isdst < 0)
  1141.       new = localtime(&end);
  1142.     else
  1143.    #endif
  1144.       new = gmtime(&end);
  1145.     if (new == NULL)
  1146.       invalid();
  1147.     new->tm_isdst = tp->tm_isdst;
  1148.     *tp = *new;
  1149.  
  1150.     return result;
  1151.   }
  1152.  #endif /* ifndef _HAVE_MKTIME */
  1153.  
  1154.  #ifndef _FTIMEDEFINED
  1155.   /*
  1156.    * these functions have to convert a MS/DOS time to a UNIX time
  1157.    * and vice versa.
  1158.    * here comes the MS/DOS time structure
  1159.    */
  1160.   struct ftime
  1161.   {
  1162.     unsigned  ft_tsec  : 5;   /* 0..59 /2 (!) */
  1163.     unsigned  ft_min   : 6;   /* 0..59 */
  1164.     unsigned  ft_hour  : 5;   /* 0..23 */
  1165.     unsigned  ft_day   : 5;   /* 1..31 */
  1166.     unsigned  ft_month : 4;   /* 1..12 */
  1167.     unsigned  ft_year  : 7; /* Year minus 1980 */
  1168.   };
  1169.  #endif
  1170.  
  1171.  /*
  1172.   * Get file's timestamp and package it into a 32-bit word (MS_DOS-format).
  1173.   * This function should work on any system :-)
  1174.   */
  1175.  ulong get_filetime (char *filename)
  1176.  {
  1177.    struct ftime fti;
  1178.    ulong *retval = (ulong *) &fti;
  1179.    struct tm *utm;
  1180.    struct stat fst;
  1181.  
  1182.    *retval = 0UL;
  1183.  
  1184.    /* get file status */
  1185.    if (stat (filename, &fst) == 0)
  1186.    {
  1187.       /* get time of last modification and convert it to MS/DOS time */
  1188.      utm = gmtime (&fst.st_mtime);
  1189.  
  1190.      if (utm)
  1191.      {
  1192.        fti.ft_tsec  = utm->tm_sec / 2;
  1193.        fti.ft_min   = utm->tm_min;
  1194.        fti.ft_hour  = utm->tm_hour;
  1195.        fti.ft_day   = utm->tm_mday;
  1196.        fti.ft_month = utm->tm_mon + 1;
  1197.        fti.ft_year  = utm->tm_year - 80;
  1198.        return (*retval);
  1199.      }
  1200.    }
  1201.  
  1202.    /* error exit */
  1203.    printf ("\007\nCan't get file's timestamp!\n");
  1204.    return (*retval);
  1205.  }
  1206.  #ifdef __unix__
  1207.   /*
  1208.    * Set file's timestamp
  1209.    * This function only works on UNIX-systems
  1210.    */
  1211.   void set_filetime (char *filename, ulong ftimestamp)
  1212.   {
  1213.     time_t atime;
  1214.     struct utimbuf utim;
  1215.     struct ftime *fti;
  1216.     struct tm utm;
  1217.  
  1218.     /* convert MS/DOS ftimestamp to UNIX atime */
  1219.     fti = (struct ftime *) &ftimestamp;
  1220.     utm.tm_sec   = fti->ft_tsec * 2;
  1221.     utm.tm_min   = fti->ft_min;
  1222.     utm.tm_hour  = fti->ft_hour;
  1223.     utm.tm_mday  = fti->ft_day;
  1224.     utm.tm_mon   = fti->ft_month - 1;
  1225.     utm.tm_year  = fti->ft_year + 80;
  1226.     utm.tm_wday  = utm.tm_yday  =  utm.tm_isdst = 0;
  1227.     atime = mktime (&utm);
  1228.  
  1229.     if (atime != -1)
  1230.     {
  1231.       /* set access time and modification time */
  1232.       utim.actime = atime;
  1233.       utim.modtime = atime;
  1234.       if (utime (filename, &utim) >= 0)
  1235.         return;
  1236.     }
  1237.  
  1238.     /* error exit */
  1239.     printf ("\007\nCan't set file's timestamp!");
  1240.     return;
  1241.   }
  1242.  #else /* not UNIX */
  1243.   /*
  1244.    * Set file's timestamp
  1245.    *
  1246.    */
  1247.   void set_filetime (char *filename, ulong ftimestamp)
  1248.   {
  1249.     /* error exit */
  1250.     printf ("\007\nset_filetime not (yet) implemented on this system!");
  1251.     return;
  1252.   }
  1253.  #endif /* __unix__ */
  1254. #endif /* __MSDOS__ or __TOS__ */
  1255.  
  1256.  
  1257. /*
  1258. *** get_hex: some compilers have real big trouble when reading hex values from
  1259. ***          a file with fscanf() that have leading zeros! e.g. 00A will be
  1260. ***          read as two separate values (0 and A)! grr!!
  1261. ***          get_hex skips all leading zeros to eliminate the problem.
  1262. ***
  1263.  */
  1264.  
  1265. uint get_hex (char *hex)
  1266. {
  1267.   register i = 0;
  1268.   uint   ret = 0;
  1269.  
  1270.   while (hex[i] == '0')
  1271.     i++;
  1272.   sscanf(hex+i, "%x", &ret);
  1273.   return (ret);
  1274. }
  1275.  
  1276.  
  1277. #ifdef _FNSPLIT
  1278. /*
  1279. ***       filenamesplit
  1280. ***       (by DL1MEN, taken from SP-ST, modified for portability)
  1281. ***
  1282. ***       split filename up into drive, path, name and extension.
  1283. ***
  1284.  */
  1285.  
  1286. void fnsplit(char *pth, char *dr, char *pa, char *fn, char *ft)
  1287. {
  1288.   char drv[MAXDRIVE], pat[MAXDIR], fna[MAXFILE], fty[MAXEXT], tmp[MAXPATH];
  1289.   char *p;
  1290.  
  1291.   strcpy(tmp,pth);
  1292.  
  1293.   if ((p = strchr(tmp,':')) != NULL)
  1294.   {
  1295.     *p++ = EOS;
  1296.     strcpy(drv,tmp);
  1297.   }
  1298.   else
  1299.   {
  1300.     p = tmp;
  1301.     drv[0] = EOS;
  1302.   }
  1303.   if ((pth = strrchr(p, PATHCHAR)) != NULL)
  1304.   {
  1305.     *pth++ = EOS;
  1306.     strcpy(pat,p);
  1307.   }
  1308.   else
  1309.   {
  1310.     pth = p;
  1311.     pat[0] = EOS;
  1312.   }
  1313.   if ((p = strchr(pth,'.')) != NULL)
  1314.   {
  1315.     strcpy(fty,p);
  1316.     fty[MAXEXT-1] = EOS;
  1317.     *p = EOS;
  1318.   }
  1319.   else
  1320.     fty[0] = EOS;
  1321.  
  1322.   strcpy(fna,pth);
  1323.   fna[MAXFILE-1] = EOS;
  1324.  
  1325.   if (dr)
  1326.   {
  1327.     strcpy(dr,drv);
  1328.     if (drv[0])
  1329.       strcat(dr,":");
  1330.   }
  1331.   if (pa)
  1332.   {
  1333.     strcpy(pa,pat);
  1334.     if (pat[0])
  1335.       strcat(pa, PATHSEP);
  1336.   }
  1337.   if (fn)
  1338.     strcpy(fn,fna);
  1339.   if (ft)
  1340.    strcpy(ft,fty);
  1341. }
  1342. #endif /** _FNSPLIT **/
  1343.  
  1344. #ifdef _ICMP
  1345. /* The following functions are unfortunately not avialable on all compilers */
  1346.  
  1347. /*
  1348. *** strupr - convert string to upper case.
  1349. ***
  1350. ***
  1351.  */
  1352.  
  1353. char *strupr (char *string)
  1354. {
  1355.   char *strcnvt (char *string, int flag);
  1356.  
  1357.   return (strcnvt (string, 1));
  1358. }
  1359.  
  1360. /*
  1361. *** strlwr - convert string to lower case.
  1362. ***
  1363. ***
  1364.  */
  1365.  
  1366. char *strlwr (char *string)
  1367. {
  1368.   char *strcnvt (char *string, int flag);
  1369.  
  1370.   return (strcnvt (string, 0));
  1371. }
  1372.  
  1373. /*
  1374. *** strcnvt - convert string to upper (flag == 1) or lower (flag == 0) case.
  1375. ***
  1376. ***
  1377.  */
  1378.  
  1379. char *strcnvt (char *string, int flag)
  1380. {
  1381.   register i = 0;
  1382.  
  1383.   while (string[i])
  1384.   {  
  1385.     string[i] = (flag)?toupper (string[i]):tolower (string[i]);
  1386.     i++;
  1387.   }
  1388.  
  1389.   return (string);
  1390. }
  1391.  
  1392. /*
  1393. *** stricmp - same as strcmp(), but ignores case.
  1394. *** s1 and s2 are not modified.
  1395. ***
  1396.  */
  1397.  
  1398. int stricmp (const char *s1, const char *s2)
  1399. {
  1400.   return (strnicmp (s1, s2, (size_t) 80));
  1401. }
  1402.  
  1403. /*
  1404. *** strnicmp - same as strncmp(), but ignores case.
  1405. *** s1 and s2 are not modified.
  1406. ***
  1407.  */
  1408.  
  1409. int strnicmp (const char *s1, const char *s2, size_t n)
  1410. {
  1411.   char _s1[81], _s2[81];
  1412.  
  1413.   strncpy (_s1, s1, 80);
  1414.   strncpy (_s2, s2, 80);
  1415.   strupr (_s1);
  1416.   strupr (_s2);
  1417.  
  1418.   return (strncmp (_s1, _s2, n));
  1419. }
  1420. #endif /** _ICMP **/
  1421.